home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / SVGALINE.ZIP / vesasvga.txt
Internet Message Format  |  1995-02-12  |  9KB

  1. From: cs94169@assn013.cs.ualberta.ca (David Bond)
  2. Newsgroups: rec.games.programmer
  3. Subject: VESA SVGA - line code and info
  4. Date: 6 Feb 1995 18:39:08 GMT
  5.  
  6. Hello everyone!
  7.  
  8. This is a mini-tutorial, and code, relating to VESA SVGA programming.  The
  9. code includes a line procedure which is based upon Bresenham's algorithm.  It
  10. is not blazingly fast, but hopefully it'll work on all SVGA cards with VESA
  11. support, and it is pretty compact - no special cases for slopes.
  12.  
  13. Many people try to begin programming in SVGA modes straight from mode 13h, or
  14. Xmode variants.  They quickly encounter the problem of only 64K of vid mem
  15. being accessable - falls a little short of the 300K required for 640x480x8bit!
  16. The special address space A000h - AFFFh must be mapped to different parts of
  17. the video memory to make use of it.  This can be done via VESA functions.  If
  18. you don't yet have 'vesasp12.txt' (PCGPE contains this document) then I
  19. suggest you get it from x2ftp.oulu.fi /pub/msdos/programming/specs/vesasp12.
  20. This document details the VESA BIOS extensions used to get info on video
  21. modes, set video modes, pan across a larger virtual screen, and set the CPU
  22. window (A000-AFFF) to map to different places in video mem.
  23.  
  24. Even though VESA provides a common interface for SVGA cards, there are still
  25. some specifics that have to be dealt with.  The 'granularity' of the window
  26. is the smallest amount by which it can be moved.  A 64KB granularity with
  27. 1MB video memory means the CPU window can be mapped to one of 16 'chunks' in
  28. this memory.  A 4KB granularity has more potential mappings - the window is
  29. still 64KB in size, but it can be positioned on any 4K boundary in video.  I
  30. know granularitys of 4K, 16K, 32K, and 64K exist.  Some cards are switchable
  31. (actually the only chipset I'm familiar with that has this option is Cirrus
  32. Logic - defaults to 4K, can be set to 16K.  I think this is necessary for
  33. accessing >1MB).
  34.  
  35. I see two ways to manage this discrepancy.  Code can assume 64K granularity
  36. always, and the 'bank-switching' routines make sure the window is moved by this
  37. ammount (4K gran would require inc/dec by 16).  The other way is to deal with
  38. each granularity differently - this is how the line code provided below
  39. operates.
  40.  
  41. Finer granularity can speed up rendering.  Line drawing will be used to
  42. illustrate.  The linear start address is calculated.  The low 16 bits of this
  43. address are mappable to the 64K window.  The high order bits can be used to
  44. locate the position of the window.  With a 64K granularity, the high word is
  45. our window location, and the low word is the displacement into the window.
  46. With 4K gran, The low 12 bits are the offset, and remaining high bits are the
  47. window location.  If a line begins near the end of a 64K aligned chunk (linear
  48. position 123840, say), and continues down a short distance, It'll cross a 64K
  49. boundary.  With 64K gran, the window will have to be moved.  Using a 4K
  50. granularity, the initial offset into a window can be kept below 4096.  So,
  51. lines that aren't too long can always be kept within the starting window.
  52.  
  53. Another advantage that fine granularity provides is easier alignment with the
  54. edge of the screen.  With a horizontal resolution of 640, 32 lines takes up 
  55. 20KB, which is divisible by 4KB.  If all windowing is then limited to be
  56. aligned on these 20KB bounds, one will never have to worry about overflowing
  57. past the end of the window while drawing across a scan-line.  The windows
  58. are positioned so that the 'bottom' of the window is on these 20K bounds.
  59. Inner rendering loops that move across a horizontal line don't bother with
  60. checking for a 'page-cross'.  The outer loop checks for overflow when it moves
  61. down to the next scan-line.  A 64K granularity doesn't align until 512
  62. vertical lines (320KB), which means the inner loop must check for 
  63. page-crossings within the scan-line.
  64.  
  65. Note: one way to create easy alignment with the edge is to change the length
  66. of a scanline to a power of 2 (say 1024).  This wastes video memory, but
  67. it can be well worth it.  Check vesasp12.txt for setting this.
  68.  
  69. The line procedure, below, does take advantage of positioning the top of the
  70. window as close to the top of the line as it can.  Thus window moving for
  71. mid-length lines is reduced for cards that have smaller granularities.  It
  72. does not take advantage of alignment with the screen edge.  The code is made
  73. to be fairly 'straight-forward', not much fancy is done - it's just simple,
  74. flexible, small, and I hope easy to understand.  One easy optimization to add
  75. is to check if the endpoints lie in different window addresses - if not, a
  76. routine without a page-cross check can be called; otherwise the standard
  77. routine is called.
  78.  
  79. Careful eyes may notice that lines are always rendered from top to bottom, but
  80. I have a macro to move the CPU window UP!  A situation where this is needed:
  81. A window begins 382 pixels across on a scan-line.  A line is started just two
  82. pixels into the window (at 383).  The endpoint is on the far left of the screen
  83. (0), and 5 pixels down from start.  The line is going to begin with a string of
  84. pixels straight to the left - passing BACKWARD through the window boundary.
  85. This occurance requires the 'PageUp' macro.  If alignment is done with the
  86. screen edge, this isn't necessary.
  87.  
  88.  
  89. This code is provided for learning purposes, and may be used in any fashion
  90. desired - it's free!  If the code doesn't work for you, please let me know.  I
  91. haven't had opportunity to test it on other systems.  It didn't get a rigorous
  92. test on mine either - paging is untested.  Conversion to other resolutions is
  93. pretty simple.  The linear address calculation is all that has to be modified
  94. (I think!?) - 'bx' may be too small at higher resoultions - use 'ebx'.
  95.  
  96. This can be assembled with:    tasm /m2 /ml <filename>
  97.                 tlink /3 <filename>
  98. Or pieces can be extracted, and interfaced to whatever you wish,
  99. however you wish.
  100.  
  101. -Anthony Tavener 'Daoloth of MetaSentience'
  102. -cs94169@cs.ualberta.ca (Temporary - friend's account)
  103.  
  104. ---CODE BEGIN---
  105. .486
  106. code    segment para public use16
  107.     assume    cs:code
  108.  
  109. PgDown        macro
  110.     push    bx
  111.     push    dx
  112.     xor    bx,bx
  113.     mov    dx,cs:winpos
  114.     add    dx,cs:disp64k
  115.     mov    cs:winpos,dx
  116.     call    cs:winfunc
  117.     pop    dx
  118.     pop    bx
  119.         endm
  120.  
  121. PgUp        macro
  122.     push    bx
  123.     push    dx
  124.     xor    bx,bx
  125.     mov    dx,cs:winpos
  126.     sub    dx,1
  127.     mov    cs:winpos,dx
  128.     call    cs:winfunc
  129.     add    di,cs:granmask
  130.     inc    di
  131.     pop    dx
  132.     pop    bx
  133.         endm
  134.  
  135.     mov    ax,seg stk    ;\
  136.     mov    ss,ax        ;.set up program stack
  137.     mov    sp,200h        ;/
  138.  
  139.     call    GetVESA        ;init variables related to VESA support
  140.  
  141.     mov    ax,4f02h    ;\
  142.     mov    bx,0101h    ;.VESA mode 101h (640x480x8bit)
  143.     int    10h        ;/
  144.  
  145.     mov    ax,0a000h
  146.     mov    ds,ax
  147.  
  148.     mov    eax,10h        ;\
  149.     mov    ebx,13h
  150.     mov    ecx,20bh    ;test Lin procedure
  151.     mov    edx,1a1h
  152.     mov    ebp,21h
  153.     call    Lin        ;/
  154.  
  155.     mov    ax,4c00h
  156.     int    21h
  157.  
  158. GetVESA        proc
  159. ;This is just a hack to get the window-function address for a direct call,
  160. ;and to initialize variables based upon the window granularity.
  161.     mov    ax,4f01h        ;\
  162.     mov    cx,0101h
  163.     lea    di,buff            ;.use VESA mode info call to..
  164.     push    cs            ;.get card stats for mode 101h
  165.     pop    es
  166.     int    10h            ;/
  167.     add    di,4
  168.     mov    ax,word ptr es:[di]    ;get window granularity (in KB)
  169.     shl    ax,0ah
  170.     dec    ax
  171.     mov    cs:granmask,ax        ; = granularity - 1 (in Bytes)
  172.     not    ax
  173.     clc
  174. GVL1:    inc    cs:bitshift        ;\
  175.     rcl    ax,1            ;.just a way to get vars I need :)
  176.     jc    GVL1            ;/
  177.     add    cs:bitshift,0fh
  178.     inc    ax
  179.     mov    disp64k,ax
  180.     add    di,8
  181.     mov    eax,dword ptr es:[di]    ;get address of window control
  182.     mov    cs:winfunc,eax
  183.     ret
  184. buff        label    byte
  185.         db    100h dup (?)
  186.         endp
  187.  
  188. Lin        proc
  189. ;Codesegment: Lin
  190. ;Inputs: eax: x1, ebx: y1, cx: x2, dx: y2, bp: color
  191. ;Destroys: ax, bx, cx, edx, si, edi
  192. ;Global: winfunc(dd),winpos(dw),page(dw),granmask(dw),disp64k(dw),bitshift(db)
  193. ;Assumes: eax, ebx have clear high words
  194.  
  195.     cmp    dx,bx            ;\
  196.     ja    LinS1            ;.sort vertices
  197.     xchg    ax,cx
  198.     xchg    bx,dx            ;/
  199.  
  200. LinS1:    sub    cx,ax            ;\
  201.     ja    LinS2            ;.calculate deltax and
  202.     neg    cx            ;.modify core loop based on sign
  203.     xor    cs:xinc1[1],28h        ;/
  204.  
  205. LinS2:    sub    dx,bx            ;deltay
  206.     neg    dx
  207.     dec    dx
  208.  
  209.     shl    bx,7            ;\
  210.     add    ax,bx            ;.calc linear start address
  211.     lea    edi,[eax][ebx*4]    ;/
  212.  
  213.     mov    si,dx            ;\
  214.     xor    bx,bx
  215.     mov    ax,cs:page    ;\
  216.     shl    ax,2        ;.pageOffset=page*5*disp64K
  217.     add    ax,cs:page
  218.     mul    cs:disp64k    ;/
  219.     push    cx            ;.initialize CPU window
  220.     mov    cl,cs:bitshift        ;.to top of line
  221.     shld    edx,edi,cl
  222.     pop    cx
  223.     add    dx,ax
  224.     and    di,cs:granmask
  225.     mov    cs:winpos,dx
  226.     call    cs:winfunc
  227.     mov    dx,si            ;/
  228.  
  229.     mov    ax,bp
  230.     mov    bx,dx
  231.  
  232. ;ax:color, bx:err-accumulator, cx:deltaX, dx:vertical count,
  233. ;di:location in CPU window, si:deltaY, bp:color
  234.  
  235. LinL1:    mov    [di],al            ;\
  236.     add    bx,cx
  237.     jns    LinS3
  238. LinE1:    add    di,280h
  239.     jc    LinR2            ;.core routine to
  240.     inc    dx            ;.render line
  241.     jnz    LinL1
  242.     jmp    LinOut
  243. LinL2:    mov    [di],al        ;\
  244. xinc1        label    byte
  245. LinS3:    add    di,1        ;.this deals with
  246.     jc    LinR1        ;.horizontal pixel runs
  247. LinE2:    add    bx,si
  248.     jns    LinL2        ;/
  249.     jmp    LinE1            ;/
  250.  
  251. LinR1:    js    LinS7            ;\
  252.     PgDown                ;.move page down 64k..
  253.     mov    ax,bp
  254.     jmp    LinE2
  255. LinS7:    PgUp                ;.or up by 'granularity'
  256.     mov    ax,bp
  257.     jmp    LinE2            ;/
  258.  
  259. LinR2:    PgDown                ;\
  260.     mov    ax,bp            ;.move page down 64k
  261.     inc    dx
  262.     jnz    LinL1            ;/
  263.  
  264. LinOut:    mov    cs:xinc1[1],0c7h
  265.     ret
  266.         endp
  267.  
  268. winfunc        dd    ?    ;fullpointer to VESA setwindow function
  269. winpos        dw    ?    ;temp storage of CPU window position
  270. granmask    dw    ?    ;masks address within window granularity
  271. disp64k        dw    ?    ;number of 'granules' in 64k
  272. page        dw    0    ;video page (0,1,2 for 1MB video)
  273. bitshift    db    0    ;used to extract high order address bits..
  274.                 ;\ for setting CPU window
  275.         ends
  276.  
  277. stk    segment para stack use16 'STACK'
  278.         dw    100h dup (?)
  279.         ends
  280.         end
  281. ---CODE END---
  282.  
  283.  
  284.